#pragma once

#include <algorithm>
#include "base.h"
#include "vector.h"

class aabb2f
{
public:
	aabb2f(const vector2f& min = {}, const vector2f& max = {})
		: min(min), max(max)
	{}

	bool contains(const vector2f& pos) const {
		return this->min.x <= pos.x && pos.x <= this->max.x &&
			this->min.y <= pos.y && pos.y <= this->max.y;
	}

	bool intersectAABBs(const aabb2f& box, aabb2f* boxIntersect = NULL) const {
		if (this->min.x > box.max.x) return false;
		if (this->max.x < box.min.x) return false;
		if (this->min.y > box.max.y) return false;
		if (this->max.y < box.min.y) return false;
		if (boxIntersect != NULL) {
			boxIntersect->min.x = std::max(this->min.x, box.min.x);
			boxIntersect->max.x = std::min(this->max.x, box.max.x);
			boxIntersect->min.y = std::max(this->min.y, box.min.y);
			boxIntersect->max.y = std::min(this->max.y, box.max.y);
		}
		return true;
	}

	float distanceAABBs(const aabb2f& box) const {
		if (this->min.x > box.max.x) {
			if (this->min.y > box.max.y) {
				return this->min.DistanceSq(box.max);
			} else if (this->max.y < box.min.y) {
				return vector2f(this->min.x, this->max.y).
					DistanceSq({box.max.x, box.min.y});
			} else {
				return SQ(this->min.x - box.max.x);
			}
		} else if (this->max.x < box.min.x) {
			if (this->min.y > box.max.y) {
				return vector2f(this->max.x, this->min.y).
					DistanceSq({box.min.x, box.max.y});
			} else if (this->max.y < box.min.y) {
				return this->max.DistanceSq(box.min);
			} else {
				return SQ(this->max.x - box.min.x);
			}
		} else {
			if (this->min.y > box.max.y) {
				return SQ(this->min.y - box.max.y);
			} else if (this->max.y < box.min.y) {
				return SQ(this->max.y - box.min.y);
			} else {
				return .0f;
			}
		}
	}

	vector2f closestPointTo(const vector2f& pos) const {
		vector2f point;
		if (pos.x < this->min.x) {
			point.x = this->min.x;
		} else if (pos.x > this->max.x) {
			point.x = this->max.x;
		} else {
			point.x = pos.x;
		}
		if (pos.y < this->min.y) {
			point.y = this->min.y;
		} else if (pos.y > this->max.y) {
			point.y = this->max.y;
		} else {
			point.y = pos.y;
		}
		return point;
	}

	bool intersectCircle(const vector2f& pos, float radius) const {
		return closestPointTo(pos).DistanceSq(pos) <= SQ(radius);
	}

	vector2f min, max;
};
